#ifndef DATA_CONNECTION_H
#define DATA_CONNECTION_H

#include "muduo/base/noncopyable.h"
#include "muduo/net/TcpConnection.h"
#include "muduo/net/InetAddress.h"

#include <memory>

namespace ftp
{

class FtpSession;
class DataAcceptor;
class FtpDataClient;
class FtpDataServer;

enum class TransferMode {
	PORT,
	PASV,
};

/**
 * Used for managing data connection
 *
 * Support two transfer mode: PORT, PASV. But only one at the same time.
 *
 * Not thread safe. Must be called in IoLoop.
 */
class DataConnection : muduo::noncopyable
	// , public std::enable_shared_from_this<DataConnection>
{
public:

	DataConnection(std::shared_ptr<FtpSession> session,
		muduo::net::EventLoop* loop,
		TransferMode mode,
		const muduo::net::InetAddress& serverAddr,
		const std::string& nameArg = std::string("DataConnection"));
	~DataConnection();

	//void connectToHost(muduo::InetAddress addr);

	//----------------------------------------------------------
	// PASV mode
	//----------------------------------------------------------

	void listen();
	bool isListening();
	muduo::net::InetAddress listenAddress() const;

	//----------------------------------------------------------
	// PORT mode
	//----------------------------------------------------------

	void connect();
	void disconnect();
	void stop();

	//----------------------------------------------------------
	// Common Interaface for PASV and PORT mode
	//----------------------------------------------------------

	bool isOpened();

	void forceClose();

	//---------------------------------------------------------
	// Set Callbacks
	//---------------------------------------------------------

	void setCallbacks(muduo::net::ConnectionCallback conncb,
		muduo::net::MessageCallback msgcb,
		muduo::net::WriteCompleteCallback writecb);

	void setConnectionCallback(muduo::net::ConnectionCallback cb)
	{
		connectionCallback_ = std::move(cb);
	}

	void setMessageCallback(muduo::net::MessageCallback cb)
	{
		messageCallback_ = std::move(cb);
	}

	void setWriteCompleteCallback(muduo::net::WriteCompleteCallback cb)
	{
		writeCompleteCallback_ = std::move(cb);
	}

	bool connected() const
	{
		return connected_;
	}

private:
	//---------------------------------------------------------
	// Data transfer
	//---------------------------------------------------------

	void onConnection(const muduo::net::TcpConnectionPtr& conn);
	void onMessage(const muduo::net::TcpConnectionPtr& conn,
		muduo::net::Buffer* buffer,
		muduo::Timestamp receiveTime);
	void onWriteComplete(const muduo::net::TcpConnectionPtr& conn);

	muduo::net::EventLoop* loop_;         // the accepter/connector loop
	std::string ipPort_;                  // string of IP address and port
	const std::string controlConnName_;   // owner control connection name
	muduo::net::InetAddress serverAddr_;
	TransferMode mode_;                   // transfer mode: PORT, PASV
	std::weak_ptr<FtpSession> weakSession_;    // owner ftp session

	// Tcp Connection Event Callback
	muduo::net::ConnectionCallback connectionCallback_;
	muduo::net::MessageCallback messageCallback_;
	muduo::net::WriteCompleteCallback writeCompleteCallback_;

	bool connected_;

	//----------------------------------------------------------
	// PORT mode
	//----------------------------------------------------------
	std::unique_ptr<FtpDataClient> client_;

	//----------------------------------------------------------
	// PASV mode
	//----------------------------------------------------------
	std::shared_ptr<FtpDataServer> server_;
};

} // namespace ftp

#endif // DATA_CONNECTION_H
